package common;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Random;

/**
 * This class manages the questions used in an exam.
 * 
 * Requests are made receive questions of a given category. Every request will
 * result in gets closer to the required points of the category requested. The
 * job of this class is to make sure that a category always receives the points
 * required without using up vital points. It resolves the problem of looping
 * for a specific point question and having too many questions on an exam.
 * 
 */
public class QuestionManager
{
	private boolean lock = false;
	//                category
	private Hashtable<Integer, ArrayList<QuestionDetails>> 
	    questions = new Hashtable<Integer, ArrayList<QuestionDetails>>();

	private Hashtable<Integer, ArrayList<QuestionDetails>> 
        backup = new Hashtable<Integer, ArrayList<QuestionDetails>>();
	
	private ArrayList<QuestionDetails>
        usedQuestions = new ArrayList<QuestionDetails>();
	
	Random rnd = new Random();
	
	public QuestionDetails getQuestion(int cat, int objective) {
		ArrayList<QuestionDetails> list = null;
		System.out.println("The cat is " + cat + " objective is " + objective);
		if(!check(cat, objective))
		{
			System.out.print("STOP! Not possible -- ");
			System.out.println("Category: "+cat+" Total: "+objective);
			return null;
		}
		
		list = questions.get(cat);
		
		QuestionDetails choice;
		
		while(list.size() > 0) 
		{
			try
			{
				choice = list.get(rnd.nextInt(list.size()));
			} catch (Exception e)
			{
				e.printStackTrace();
				return null;
			}
			
			list.remove(choice);
			
			if(!check(cat, objective - choice.points))
			{
				list.add(choice);
			}
			else
				return choice;
		
		}
		
		return null;
	}

	/**
	 * Resets the manager so that it can be used to generate another exam.
	 * 
	 * @return Returns itself in a reset form.
	 */
	public QuestionManager reset() {
		ArrayList<QuestionDetails> list;
		
		questions.clear();
		usedQuestions.clear();
		
		for(int key : backup.keySet()) {
			list = new ArrayList<QuestionDetails>();
			for(QuestionDetails qd : backup.get(key))
				list.add(qd);
			questions.put(key, list);
		}
		
		return this;
	}
	
	/**
	 * Check that a category has enough points.
	 * 
	 * @param category Category interested in.
	 * @param objective The objective points wanted for a category.
	 * @return Returns true if the objective can be reached, false if
	 * you are asking too much.
	 */
	public boolean check(int category, int objective)
	{
		System.out.println("The objective is " + objective + " and the category is " + category);
		if(objective == 0)
			return true;
		else if (objective < 0)
			return false;
		
		for(QuestionDetails qd : questions.get(category))
		{
			if(!usedQuestions.contains(qd))
			{
				usedQuestions.add(qd);
				if(check(category, objective - qd.points))
				{
					usedQuestions.remove(qd);
					return true;
				}
				
				usedQuestions.remove(qd);
			}
				System.out.println("used questions contains" + qd.getID());
		}
		return false;
	}
	
	/**
	 * Locks from adding new details and totals information.
	 */
	protected void finish()
	{
		lock = true;
	}
	
	/**
	 * Adds details of a question to be managed.
	 * 
	 * @param qd The details of a question.
	 * @throws Exception 
	 */
	protected void add(QuestionDetails qd) throws Exception
	{
		if(lock)
			throw new Exception("QuestionManager Locked");
		
		ArrayList<QuestionDetails> list = questions.get(qd.cat);
		ArrayList<QuestionDetails> list2 = backup.get(qd.cat);
		
		if (list == null)
		{
			// If there are no points create the list and add to hash.
			list = new ArrayList<QuestionDetails>();
			list2 = new ArrayList<QuestionDetails>();
			questions.put(qd.cat, list);
			backup.put(qd.cat, list2);
		}
		// Add item to the list.
		list.add(qd);
		list2.add(qd);
	}
}
